﻿<#
#=======================================================================================
# Name: PrepareActiveDirectory.ps1
# Version: 0.2
# Author: Raphael Perez - raphael@rflsystems.co.uk
# Date: 10/01/2013
# Comment: This script will prepare the active directory environment
# 
# Updates:
#        0.1 - Raphael Perez - 05/10/2012 - Initial Script
#        0.2 - Raphael Perez - 10/02/2013
#                      - Creating Universal Group for the Exchange Connector
#                      - Fixed adding security rights to System Management container
#                      - Fixed error when computer names were empty
#                      - Added try/finally
#
# Usage:
#		 Option 1: powershell.exe -ExecutionPolicy Bypass .\PrepareActiveDirectory.ps1 [Parameters]
#        Option 2: Open Powershell and execute .\PrepareActiveDirectory.ps1 [Parameters]
#
# Parameters: (All parameters are optional, if you do not use, script will ask you to provide the information)
#        Action - ad/schema - if schema, it will run the extadsch.exe, otherwise, will create OU's, computers, etc.. if needed
#        ouParent - active directory OU, if it does not exist, it will be created. You can use ',' for more than 1 parent (ie: Headquarters,New Ou,New Ou'
#        OUComputers - OU where the cm12 servers will reside. it will be created unser the ouParent
#        ComputerNames - name of the computers that will be part of the sccm infrastructure. if the computer account does not exist will be created
#        OUGroup - OU for Groups
#        ServersGroupName - Group name for the SCCM Servers
#        AdminsGroupName - Group name for the SCCM Admins
#        OUSA - OU for Service Accounts
#        SSRSAccountCreation - y/n - Create or not a service account for SQL Server Reporting Services Execution Account (SSRS)
#        SSRSAccount - only used if SSRSAccountCreation = 'y' - username
#        SSRSAccountPassword - only used if SSRSAccountCreation = 'y' - password
#        NAAccountCreation - y/n - Create or not a service account for Network Access Account
#        NAAccount - only used if NAAccountCreation = 'y' - username
#        NAAccountPassword - only used if NAAccountCreation = 'y' - password
#        ClientPushAccountCreation - y/n - Create or not a service account for Client Push
#        ClientPushAccount - only used if ClientPushAccountCreation = 'y' - username
#        ClientPushAccountPassword - only used if ClientPushAccountCreation = 'y' - password
#        exchAccountCreation - y/n - Create or not a service account for connection with exchange
#        exchAccount - only used if exchAccountCreation = 'y' - username
#        exchAccountPassword - only used if exchAccountCreation = 'y' - password
#        exchgroup - only used if exchAccountCreation = 'y' - group to be used by the Create_ExchangeConnectorRoleAndAssignment.ps1 script
#        joindomainAccountCreation - y/n - Create or not a service account for adding computers to the domain
#        joindomain - only used if joindomainAccountCreation = 'y' - username
#        joindomainPassword - only used if joindomainAccountCreation = 'y' - password
#        joindomainRights - only used if joindomainAccountCreation = 'y' - y/n - add rights to the joindomain account to add computers to the domain (these rights are added at DOMAIN LEVEL and not OU LEVEL)
#
# Examples:
#        .\PrepareActiveDirectory.ps1 -Action "ad" -ouParent 'Test,Headquarters' -ouComputers 'SCCM Servers' -ComputerNames 'SCCM01,SCCM02' -OUGroup 'Groups' -OUSA 'Service Accounts' -ServersGroupName 'SCCM Servers' -AdminsGroupName 'SCCM Admins' -SSRSAccountCreation 'y' -SSRSAccount 'ssrsea' -SSRSAccountPassword 'Pa$$w0rd' -NAAccountCreation 'y' -NAAccount 'sccmna' -NAAccountPassword 'Pa$$w0rd' -ClientPushAccountCreation 'y' -ClientPushAccount 'sccmpush' -ClientPushAccountPassword 'Pa$$w0rd' -exchAccountCreation 'y' -exchAccount 'sccmexch' -exchAccountPassword 'Pa$$w0rd' -exchgroup 'SCCM Exchange Connector Servers' -joindomainAccountCreation 'y' -joindomain 'sccmjoindomain' -joindomainPassword 'Pa$$w0rd' -joindomainRights 'y'
#        - will prepare the active diretory. create a ou called test and a child ou called Headquarters if it does not exist
#        - create child ou SCCM Servers, Groups, Service Accounts
#        - create group SCCM Servers and SCCM Admins
#        - create computer accounts SCCM01, SCCM02 and add it to the sccm servers group
#        - add the user running the script to the sccm admins group
#        - create a ssrsaccount (ssrsea), network account (sccmna), clientpush account (sccmpush), exchange connector (sccmexch)
#        - create a joindomainaccount (sccmjoindomain) and will give rights to add computers to the domain at DOMAIN LEVEL
#
#        .\PrepareActiveDirectory.ps1 -Action "schema"
#        - schema extension
#=======================================================================================
#>
PARAM(
    $Action = '',
    $ouParent = '',
    $OUComputers = '',
    $ComputerNames = '',
    $OUGroup = '',
    $ServersGroupName = '',
    $AdminsGroupName = '',
    $OUSA = '',
    $SSRSAccountCreation = '',
    $SSRSAccount = '',
    $SSRSAccountPassword = '',    
    $NAAccountCreation = '',
    $NAAccount = '',
    $NAAccountPassword = '',
    $ClientPushAccountCreation = '',
    $ClientPushAccount = '',
    $ClientPushAccountPassword = '',
    $exchAccountCreation = '',
    $exchAccount = '',
    $exchAccountPassword = '',
	$exchgroup = '',
    $joindomainAccountCreation = '',
    $joindomain = '',
    $joindomainPassword = '',
    $joindomainRights = ''
)
try
{
    $ErrorActionPreference = "Stop" 
    $maxretry = 5
    $MediaFolder = $MediaFolder = (Get-Item (Get-Location).Path).Parent.FullName
    if ($MediaFolder -eq '') { (Get-Location).Path }
    if ($mediaFolder.substring($mediaFolder.length-1) -ne '\') { $mediaFolder += '\' }        

    if (!(Test-Path -Path .\Functions.ps1))
    {
        Write-Host "Module Functions.ps1 does not exist on the current folder, no futher action taken" -ForegroundColor Red
    }
    else
    {
        Import-Module -name .\Functions.ps1
    }

    $scriptName = ($MyInvocation.MyCommand.Name)
    $StrDateTime = Get-Date -uformat "%d%m%Y-%H%M"
    $path = $MediaFolder + "_Logs\" + ($MyInvocation.MyCommand.Name -replace '.ps1', '') + ".log"
    $component = ($MyInvocation.MyCommand.Name -replace '.ps1', '')
    New-Item ($MediaFolder + '_Logs') -type directory -force | out-null 
    try
    {
        New-Item ($MediaFolder + '_Logs\Test.log') -type file -force | out-null 
        Remove-Item ($MediaFolder + '_Logs\Test.log') -force | out-null 
    }
    catch
    {
        Write-Host "Unable to read/write file on $MediaFolder folder, no futher action taken" -ForegroundColor Red
        Exit    
    }

    [Environment]::SetEnvironmentVariable("SEE_MASK_NOZONECHECKS", "1", "Process")

    if (!(Test-IsAdmin)) { Exit }
    if (!(Test-PowerShell64)) { Exit }
    if (!(Test-IsMediaFolderExist -MediaFolder $MediaFolder)) { Exit }

    $Action = (BuildAnswer -return $action -Question "Enter the Action to be taken" -options "AD/Schema" -default "AD").ToLower()
    if ($Action -eq 'ad')
    {
        $ouParent = BuildAnswer -return $ouParent -question "Enter the OU Parent where the sub-OUs are going to be created" -allowblank $false -errorMsg 'OU Parent' 
        $OUComputers = BuildAnswer -return $OUComputers -question "Enter the Servers OU Name" -default "SCCM Servers"  -allowblank $false -errorMsg 'Servers OU Name'
        $ComputerNames = BuildAnswer -return $ComputerNames -question "Enter the computer names that will be part of the SCCM Infrastructure"

        $OUGroup = (BuildAnswer -return $OUGroup -question "Enter the Groups OU Name" -default "Groups")
        $ServersGroupName = (BuildAnswer -return $ServersGroupName -question "Enter the SCCM Servers AD Security Group" -default "SCCM Servers")
        $AdminsGroupName = (BuildAnswer -return $AdminsGroupName -question "Enter the SCCM Admins AD Security Group" -default "SCCM Admins")
        $OUSA = (BuildAnswer -return $OUSA -question "Enter the Service Account OU Name" -default "Service Accounts")
        
        $SSRSAccountCreation = (BuildAnswer -return $SSRSAccountCreation -question "Create SQL Server Reporting Services Execution Account" -options "y/n" -default "n").ToLower()
        if ($SSRSAccountCreation -eq 'y')
        {
            $return = Get-UserNamePassword -username $SSRSAccount -password $SSRSAccountPassword -question "Enter the SSRS Account" -errorMsg 'SSRS Account' -testaccount $false
            $SSRSAccount = $return[0]
            $SSRSAccountPassword = $return[1]
        }
        
        $NAAccountCreation = (BuildAnswer -return $NAAccountCreation -question "Create Network Access Account" -options "y/n" -default "n").ToLower()
        if ($NAAccountCreation -eq 'y')
        {
            $return = Get-UserNamePassword -username $NAAccount -password $NAAccountPassword -question "Enter the Network Access Account" -errorMsg 'Network Access Account'  -testaccount $false
            $NAAccount = $return[0]
            $NAAccountPassword = $return[1]
        }
        
        $ClientPushAccountCreation = (BuildAnswer -return $ClientPushAccountCreation -question "Create Client Push Account" -options "y/n" -default "n").ToLower()    
        if ($ClientPushAccountCreation -eq 'y')
        {
            $return = Get-UserNamePassword -username $ClientPushAccount -password $ClientPushAccountPassword -question "Enter the Client Push Account" -errorMsg 'Client Push Account'  -testaccount $false
            $ClientPushAccount = $return[0]
            $ClientPushAccountPassword = $return[1]
        }
        
        $exchAccountCreation = (BuildAnswer -return $exchAccountCreation -question "Create Exchange Access Account" -options "y/n" -default "n").ToLower()    
        if ($exchAccountCreation -eq 'y')
        {
            $return = Get-UserNamePassword -username $exchAccount -password $exchAccountPassword -question "Enter the Exchange Connector Account" -errorMsg 'Exchange Connector Account'  -testaccount $false
            $exchAccount = $return[0]
            $exchAccountPassword = $return[1]
    		
    		$exchgroup = (BuildAnswer -return $exchgroup -question "Security Group name for SCCM Exchange Connector" -default "SCCM Exchange Connector Servers")
        }
        
        $joindomainAccountCreation = (BuildAnswer -return $joindomainAccountCreation -question "Create Join Domain Account" -options "y/n" -default "n").ToLower()
        if ($joindomainAccountCreation -eq 'y')
        {
            $return = Get-UserNamePassword -username $joindomain -password $joindomainPassword -question "Enter the Join Domain Account" -errorMsg 'Join Domain Account'  -testaccount $false
            $joindomain = $return[0]
            $joindomainPassword = $return[1]
            
            $joindomainRights = (BuildAnswer -return $joindomainRights -question "Give Join Domain Account rights to Domain" -options "y/n" -default "n").ToLower()
        }
    }

    Write-Log -Message "MediaFolder: $MediaFolder"
    Write-Log -Message "Action: $Action"
    if ($Action -eq 'ad')
    {
        Write-Log -Message "OUComputers: $OUComputers"
        Write-Log -Message "ComputerNames: $ComputerNames"

        Write-Log -Message "OUGroup: $OUGroup"
        Write-Log -Message "OUParent: $ouParent"
        Write-Log -Message "ServerGroupName: $ServersGroupName"
        Write-Log -Message "AdminGroupName: $AdminsGroupName"
        
        Write-Log -Message "OUSA: $OUSA"
        Write-Log -Message "SSRSAccountCreation: $SSRSAccountCreation"
        Write-Log -Message "SSRSAccount: $SSRSAccount"
        Write-Log -Message "SSRSAccountPassword: ******"
        
        Write-Log -Message "NAAccountCreation: $NAAccountCreation"
        Write-Log -Message "NAAccount: $NAAccount"
        Write-Log -Message "NAAccountPassword: ******"

        Write-Log -Message "ClientPushAccountCreation: $ClientPushAccountCreation"
        Write-Log -Message "ClientPushAccount: $ClientPushAccount"
        Write-Log -Message "ClientPushAccountPassword: ******"
        
        Write-Log -Message "exchAccountCreation: $exchAccountCreation"
        Write-Log -Message "ExchangeAccount: $exchAccount"
        Write-Log -Message "ExchangeAccountPassword: ******"

        Write-Log -Message "joindomainAccountCreation: $joindomainAccountCreation"
        Write-Log -Message "JoinDomainAccount: $joindomain"
        Write-Log -Message "JoinDomainAccountPassword: ******"
        Write-Log -Message "joindomainRights: $joindomainRights"
    }
    elseif ($Action -eq 'schema')
    {
        if (!(Test-IsFileExist -filename ($MediaFolder + "ConfigMgr2012\SP1\SMSSETUP\BIN\X64\extadsch.exe"))) { Exit }
    }

    if ($Action -eq 'ad')
    {
        Import-Module ActiveDirectory
        $root = (Get-ADRootDSE).defaultNamingContext

        if ((CreateADOU -OUName ($ouParent + ',' + $OUComputers)) -eq $false) { Exit }
        if ((CreateADOU -OUName ($ouParent + ',' + $OUGroup)) -eq $false) { Exit }
        if ((CreateADOU -OUName ($ouParent + ',' + $OUSA) )-eq $false) { Exit }
        if ((CreateADGroup -GroupName $ServersGroupName -OUName ($ouParent + ',' + $OUGroup)) -eq $false) { Exit }
        if ((CreateADGroup -GroupName $AdminsGroupName -OUName ($ouParent + ',' + $OUGroup)) -eq $false) { Exit }

        if ($computernames -ne '')
        {
            $cNames = $computernames.split(',') -replace ' ',''
            foreach ($computer in $cNames)
            {
                if ((CreateADComputer -Name $computer -OUName ($ouParent + ',' + $OUComputers)) -eq $false) { Exit }
                Add-ComputerToADGroup -ComputerName $computer -GroupName $ServersGroupName
            }    
            
            Add-UserToADGroup -UserName ($env:UserName) -GroupName $AdminsGroupName
        }
        
        if ($SSRSAccountCreation -eq 'y') { Create-ADUser -UserName $SSRSAccount -Password $SSRSAccountPassword -OUName ($ouParent + ',' + $OUSA) }
        if ($NAAccountCreation -eq 'y') { Create-ADUser -UserName $NAAccount -Password $NAAccountPassword -OUName ($ouParent + ',' + $OUSA) }
        if ($ClientPushAccountCreation -eq 'y') { Create-ADUser -UserName $ClientPushAccount -Password $ClientPushAccountPassword -OUName ($ouParent + ',' + $OUSA) }
        if ($exchAccountCreation -eq 'y') 
    	{
    		Create-ADUser -UserName $exchAccount -Password $exchAccountPassword -OUName ($ouParent + ',' + $OUSA) 
    	    if ((CreateADGroup -GroupName $exchgroup -OUName ($ouParent + ',' + $OUGroup) -Universal $true) -eq $false) { Exit }
    		Add-UserToADGroup -UserName ($exchAccount) -GroupName $exchgroup		
    	}
    	
        if ($joindomainAccountCreation -eq 'y') 
        { 
            Create-ADUser -UserName $joindomain -Password $joindomainPassword -OUName ($ouParent + ',' + $OUSA) 
            if ($joindomainRights -eq 'y')
            {
            
                Write-Log -Message "Permissions for Domain $root...Starting"

                $objUser = Get-ADUser -Filter "name -eq '$joindomain'"

                $objectComputerguid = new-object Guid bf967a86-0de6-11d0-a285-00aa003049e2
                $acl = get-acl "ad:$root"
                
                $ace1 = new-object System.DirectoryServices.ActiveDirectoryAccessRule $objUser.SID, "CreateChild, DeleteChild", "Allow", $objectComputerguid, "SelfAndChildren"
                $acl.AddAccessRule($ace1)
                
                $objectExtendedRightGUID = new-object Guid bf967a86-0de6-11d0-a285-00aa003049e2
                $ace2 = new-object System.DirectoryServices.ActiveDirectoryAccessRule $objUser.SID, "ReadProperty, WriteProperty, ReadControl, WriteDacl", "Allow", "Descendents", $objectExtendedRightGUID
                $acl.AddAccessRule($ace2)
                
                $objectExtendedRightGUID2 = new-object Guid 00299570-246d-11d0-a768-00aa006e0529
                $ace3 = new-object System.DirectoryServices.ActiveDirectoryAccessRule $objUser.SID,"ExtendedRight", "Allow", $objectExtendedRightGUID2, "Descendents", $objectComputerguid
                $acl.AddAccessRule($ace3) 
                
                $objectExtendedRightGUID3 = new-object Guid ab721a53-1e2f-11d0-9819-00aa0040529b
                $ace4 = new-object System.DirectoryServices.ActiveDirectoryAccessRule $objUser.SID,"ExtendedRight", "Allow", $objectExtendedRightGUID3, "Descendents", $objectComputerguid
                $acl.AddAccessRule($ace4) 
                
                $objectExtendedRightGUID4 = new-object Guid 72e39547-7b18-11d1-adef-00c04fd8d5cd
                $ace5 = new-object System.DirectoryServices.ActiveDirectoryAccessRule $objUser.SID,"Self", "Allow", $objectExtendedRightGUID4, "Descendents", $objectComputerguid
                $acl.AddAccessRule($ace5) 

                $objectExtendedRightGUID5 = new-object Guid f3a64788-5306-11d1-a9c5-0000f80367c1
                $ace6 = new-object System.DirectoryServices.ActiveDirectoryAccessRule $objUser.SID,"Self", "Allow", $objectExtendedRightGUID5, "Descendents", $objectComputerguid
                $acl.AddAccessRule($ace6)
                
                Set-acl -aclobject $acl "ad:$root"            
                Write-Log -Message "Permissions for Domain $root...Done"
            }
        }    
        
        $objOU = ("OU=$OUGroup,$ouParent,$root") -replace ',,', ','
        
        $root = (Get-ADRootDSE).defaultNamingContext
        $arrOU = ($ouParent + ',' + $OUGroup).split(',')    
        $objOU = ''
        foreach ($ou in $arrOU)
        { 
            if ($objOU -ne '') { $objOU = ',' + $objOU }
            $objOU = "OU=$ou" + $objOU
        }
        
        $objOU += ",$root"

        
        if (!([adsi]::Exists("LDAP://CN=System Management,CN=System,$root")))
        {
            Write-Log -Message "Object CN=System Management,CN=System,$root...Creating"
            try
            {
                $smcontainer = New-ADObject -Type Container -name "System Management" -Path "CN=System,$root" -Passthru         
            }
            catch
            {
                Write-Log -Message ("An exception happen: "+$_ +"...stopping script") -severity 3
                Exit        
            }
            Write-Log -Message "Object CN=System Management,CN=System,$root...Done"
        }
        else
        {
            Write-Log -Message "Using existing object CN=System Management,CN=System,$root"
        }

        Write-Log -Message "Permissions for Object CN=System Management,CN=System,$root...Starting"
        $acl = get-acl "ad:CN=System Management,CN=System,$root"

        $objGroup = Get-ADGroup -filter {Name -eq $ServersGroupName}
        if ($objGroup -eq $null)
        {
            Write-Log -Message "Unable to find Group $ServersGroupName" -severity 3
        }
        else
        {
            $All = [System.DirectoryServices.ActiveDirectorySecurityInheritance]::SelfAndChildren
            
            $ace = new-object System.DirectoryServices.ActiveDirectoryAccessRule $objGroup.SID, "GenericAll", "Allow", $All

            $acl.AddAccessRule($ace) 
            Set-acl -aclobject $acl "ad:CN=System Management,CN=System,$root"
            Write-Log -Message "Permissions added to container System Management to Group $ServersGroupName"
        }
        Write-Log -Message "Object CN=System Management,CN=System,$root...Done"
    }
    elseif ($Action -eq 'schema')
    {
        Write-Log -Message "Extending AD Schema...Starting"
        Write-Log -Message ("Commandline: "+$MediaFolder+"ConfigMgr2012\SP1\SMSSETUP\BIN\X64\extadsch.exe")
        Run-CommandLine -commandline ($MediaFolder + "ConfigMgr2012\SP1\SMSSETUP\BIN\X64\extadsch.exe")
        Write-Log -Message "Extending AD Schema...Done"

        $ExtAdSchlog = Get-Content ($env:SystemDrive + '\ExtAdSch.log')
        if (([string]$ExtAdSchlog).IndexOf('Successfully extended the Active Directory schema.') -ge 0)
        {
            Write-Log -Message "Extending AD Schema has been extended successfully"
        }
        else
        {
            Write-Log -Message 'Error validating AD Schema Extension, no furhter action taken' -severity 3
        }
    }

    Write-Log -Message "Execution of $scriptName terminated"
}
finally
{
    $module = Get-Module -name Functions | where-object {$_.ModuleType -eq "Script"}
    if ($module -ne $null) 
    { 
        if ($module.Path.ToLower() -eq ($MediaFolder.ToLower() + "scripts\functions.ps1")) { Remove-Module $module }
    }
}     